logging <- R6::R6Class("logging",
  public = list(
    name = NULL,
    log_file_path = NULL,
    set_level = NULL,
    set_time_format = NULL,
    set_msg_format = NULL,
    msgs = list(),
    initialize = \(name = "my_log", log_file_path = NULL, set_level = "INFO",
      set_time_format = "%Y-%m-%d %H:%M:%S", set_msg_format = "{name} [{time}]: {msg}"){
      library(stringr)

      self$name <- name
      self$log_file_path <- log_file_path
      if (!is.null(log_file_path)) self$log_file_path <- log_file_path
      self$set_level <- set_level
      self$set_time_format <- set_time_format
      self$set_msg_format <- set_msg_format
    },
    info = \(msg = NULL) {
      msg_ <- private$msg2chr(msg)

      if(self$set_level != 'DEBUG') cli::cli_alert_info(msg_)

      self$msgs <- private$collect_msgs(msg_)
      private$save_log()
    },
    warning = \(msg = NULL) {
      msg_ <- private$msg2chr(msg)

      if(self$set_level != 'DEBUG') cli::cli_alert_warning(msg_)

      self$msgs <- private$collect_msgs(msg_)
      private$save_log()
    },
    error = \(msg = NULL) {
      msg_ <- private$msg2chr(msg)

      if(self$set_level != 'DEBUG') cli::cli_alert_danger(msg_)

      self$msgs <- private$collect_msgs(msg_)
      private$save_log()
    },
    success = \(msg = NULL) {
      msg_ <- private$msg2chr(msg)

      if(self$set_level != 'DEBUG') cli::cli_alert_success(msg_)

      self$msgs <- private$collect_msgs(msg_)
      private$save_log()
    },
    help = \(){
      message("
        Create a new log object using the logging$new() function, with optional parameters:
            - `name` :indicates the log name in log. The default value is 'my_log'
            - `log_file_path`: specifies the log file output path. The default value is `NULL`. No file output is performed
            - `set_level`: indicates the log level. The default value is 'INFO'
            - `set_time_format`:indicates the time format. The default value is '%Y-%m-%d %H:%M:%S'.
            - `set_msg_format`: log format, defaults to '{level} {name} [{time}]: {msg}'

        Usage:
            logger = logging$new(name = 'test',log_file_path = './log_test.log')
            logger$info('test info')
            # ℹ INFO-test [2024-07-19 13:51:58]: test info
            logger$warning('test warning')
            # ! INFO test [2024-07-19 13:51:58]: test warning
            logger$error('test error')
            # ✖ INFO test [2024-07-19 13:51:58]: test error

            # file log_test.log:
            # INFO test [2024-07-19 13:51:58]: test info
            # INFO test [2024-07-19 13:51:58]: test warning
            # INFO test [2024-07-19 13:51:58]: test error

        Other:
            logger$msgs : print all logs
        ")
    }
  ), private = list(
    msg2chr = \(msg_in_msg2chr = NULL){
      formatted_time <- format(Sys.time(), self$set_time_format)

      level <- self$set_level
      name <- self$name
      time <- formatted_time
      msg <- str_glue(msg_in_msg2chr)

      msg_chr <- str_glue(self$set_msg_format)
      return(msg_chr)
    },
    collect_msgs = \(...){
      self$msgs <- c(self$msgs, list(...))
    },
    save_log = \(){
      if (!is.null(self$log_file_path)) {
        if (!file.exists(self$log_file_path)) {
          dir.create(dirname(self$log_file_path), recursive = T, showWarnings = F)
        }
        msg_last <- self$msgs[[length(self$msgs)]]
        readr::write_lines(x = msg_last, file = self$log_file_path, append = TRUE)
      }
    }
  )
)
